import os
import sys
import time
import struct
import socket
from fcntl import ioctl
from select import select
from threading import Thread
from ipaddress import ip_network
from django.core.management import BaseCommand

VPN_CLIENT_CONF={
    'PASSWORD': b'4fb88ca224e',
    'BIND_ADDRESS': 'liuchenxi.love',
    'BIND_PORT': 5010,
    'BUFFER_SIZE': 4096,
    'MTU': 1400,
}

TUNSETIFF = 0x400454ca
IFF_TUN   = 0x0001
IFF_TAP   = 0x0002


class VpnClient():
    def __init__(self, conf):
        self.PASSWORD = conf['PASSWORD']
        self.BIND_ADDRESS = conf['BIND_ADDRESS']
        self.BIND_PORT = conf['BIND_PORT']
        self.BUFFER_SIZE = conf['BUFFER_SIZE']
        self.MTU = conf['MTU']

        self.NET_MASK = '255.255.255.0'
        self.LOCAL_IP = '192.168.255.100'
        self.to = (self.BIND_ADDRESS, self.BIND_PORT)

        self.tunfd, self.tunName = self.createTunnel()
        self.startTunnel(self.tunName)
        self.readables = []
        self.udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.readables.append(self.udp)
        self.readables.append(self.tunfd)
        
        print('Server listen on %s:%s...' % (self.BIND_ADDRESS, self.BIND_PORT))

    def createTunnel(self, tunName='tun%d',tunMode=IFF_TUN):
        tunfd = os.open("/dev/net/tun", os.O_RDWR)
        ifn = ioctl(tunfd, TUNSETIFF, struct.pack(b"16sH", tunName.encode(), tunMode))
        tunName = ifn[:16].decode().strip("\x00")
        return tunfd,tunName
    
    def startTunnel(self, tunName):
        print(os.popen('ifconfig %s %s netmask %s mtu %s up' % (tunName, self.LOCAL_IP, self.NET_MASK, self.MTU)).read())


    def _run_forever(self):
        while True:
            readab = select(self.readables, [], [], 1)[0]
            for r in readab:
                if r == self.udp:
                    #服务器监听远端接口
                    data, addr = self.udp.recvfrom(self.BUFFER_SIZE)
                    os.write(self.tunfd, data)
                    print(f'recv from {addr}  and write to funfd')
                else:
                    data = os.read(r, self.BUFFER_SIZE)
                    self.udp.sendto(data, self.to)
                    print(f'recv from tunfd and write to remote addr is {self.to}')

    def run_forever(self):
        try:
            self._run_forever()
        except KeyboardInterrupt:
            pass 
class Command(BaseCommand):
    def handle(self, *args, **options):
        clent = VpnClient(VPN_CLIENT_CONF)
        clent.run_forever()
